import requests
import json
import time
from typing import List, Dict
import itertools
import os
import signal
import sys
import random

# Kimi API配置
API_KEY = "sk-mzyKxtqDa8kOky742LexeK9zLqxv5grcquurtX2GNz2h8rFo"
API_URL = "https://api.moonshot.cn/v1/chat/completions"

# 所有场景和基础维度列表
scenarios = [
    "场地氛围", "寒暄破冰", "微表情捕捉", "抗拒信号", "数据展示时机", 
    "团队故事", "价值主张", "行程节奏", "参观引导", "餐桌微动作", 
    "需求暗线", "让步表情", "收尾信号", "估值攻防", "风险质疑", 
    "条款表情", "愿景共鸣", "权责试探", "信任信号", "供应商评估", 
    "价格谈判", "合同博弈"
]

base_dimensions = [
    "微表情识别", "身体语言解读", "语音语调分析", "语境与背景理解", 
    "情感感知", "意图推断", "文化敏感性", "权力动态分析", 
    "诚信度评估", "压力管理", "融洽关系建立", "说服技巧识别", 
    "冲突检测与解决", "积极倾听应用", "决策信号识别"
]

# 创建情境复杂度维度 - 更实用且具体
complexity_levels = [
    "基础单线索",      # 单一明显的非语言线索
    "多线索组合",      # 多个相关线索需要综合分析
    "矛盾线索",        # 相互矛盾的线索需要权衡判断
    "时间压力",        # 需要快速判断的情境
    "文化差异",        # 涉及跨文化因素的复杂情境
    "高风险决策"       # 决策后果重大的复杂情境
]

# 提示词模板 - 针对情境复杂度进行了优化
COMPLEXITY_PROMPT_TEMPLATE = """
你是一位资深的商业教练和人力资源专家，擅长沟通、谈判和情绪智能（EQ）培训。你的任务是创建用于训练"商业察言观色能力"的练习题。

请根据以下要求生成一道题目：

1. 核心场景：{scenario}
2. 能力维度：{dimension}
3. 情境复杂度：{complexity}
4. 题目形式：单选题
5. 题目结构：
   - 情境描述 (3-4句话)：详细描述一个商业场景、人物关系和当前对话状态，体现指定的情境复杂度。
   - 关键观察点 (2-3句话)：描述对方具体的非语言行为或语言特征，与情境复杂度相匹配。
   - 问题：基于这个观察，提问这意味着什么或接下来最好怎么做。
   - 选项：提供4个选项（A-D），其中只有1个是最合理、最专业的解读或行动建议。
   - 答案与解析：明确指出正确答案，并用2-3句话详细解释为什么这个选项正确，以及其他选项为什么错误或不佳。

请开始生成题目，严格遵循上述结构，特别注意体现指定的情境复杂度。
"""

# 全局变量用于处理中断信号
interrupted = False

def signal_handler(sig, frame):
    global interrupted
    print('\n正在接收中断信号，准备安全退出...')
    interrupted = True

def is_valid_question(question: Dict) -> bool:
    """检查题目是否有效（非空且包含必要字段）"""
    if not question.get('success', False):
        return False
    
    question_content = question.get('question', '')
    if not question_content or '生成失败' in question_content or len(question_content.strip()) < 50:
        return False
    
    return True

def generate_question(scenario: str, dimension: str, complexity: str) -> Dict:
    """使用Kimi API生成单个题目"""

    # 构建提示词
    prompt = COMPLEXITY_PROMPT_TEMPLATE.format(scenario=scenario, dimension=dimension, complexity=complexity)

    # API请求头
    headers = {
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    }

    # API请求数据
    data = {
        "model": "moonshot-v1-128k",  # 使用Kimi的最好模型
        "messages": [
            {"role": "system", "content": "你是一位专业的商业培训师，专注于情商和商业沟通技能的培养。"},
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.7,  # 控制创造性，0.7在专业性和多样性间取得平衡
        "max_tokens": 1500,  # 确保有足够长度生成完整题目
        "top_p": 0.9,  # 核采样参数，控制多样性
        "frequency_penalty": 0.2,  # 减少重复内容
        "presence_penalty": 0.1  # 鼓励新话题
    }

    max_retries = 5  # 增加重试次数
    for attempt in range(max_retries):
        try:
            # 发送API请求
            response = requests.post(API_URL, headers=headers, json=data, timeout=30)
            
            # 如果遇到429错误（请求过多），等待一段时间后重试
            if response.status_code == 429:
                wait_time = (2 ** attempt) + random.uniform(1, 3)  # 指数退避加随机化
                print(f"遇到API速率限制，等待 {wait_time:.2f} 秒后重试... (尝试 {attempt + 1}/{max_retries})")
                time.sleep(wait_time)
                continue
                
            response.raise_for_status()  # 检查HTTP错误

            result = response.json()
            answer = result['choices'][0]['message']['content']
            
            # 检查返回内容是否有效
            if not answer or len(answer.strip()) < 50:
                raise ValueError("返回内容过短或为空")

            return {
                "scenario": scenario,
                "dimension": dimension,
                "complexity": complexity,
                "question": answer,
                "success": True
            }

        except Exception as e:
            if attempt < max_retries - 1:  # 如果不是最后一次尝试，等待后重试
                wait_time = (2 ** attempt) + random.uniform(1, 3)
                print(f"生成题目时出错 (场景: {scenario}, 维度: {dimension}, 复杂度: {complexity}): {str(e)}")
                print(f"等待 {wait_time:.2f} 秒后重试... (尝试 {attempt + 1}/{max_retries})")
                time.sleep(wait_time)
            else:
                print(f"生成题目失败 (场景: {scenario}, 维度: {dimension}, 复杂度: {complexity}): {str(e)}")
                return {
                    "scenario": scenario,
                    "dimension": dimension,
                    "complexity": complexity,
                    "question": f"生成失败: {str(e)}",
                    "success": False
                }
    
    # 如果所有重试都失败了
    return {
        "scenario": scenario,
        "dimension": dimension,
        "complexity": complexity,
        "question": "生成失败: 达到最大重试次数",
        "success": False
    }


def load_existing_questions(filename: str = "sanwei_questions.json") -> List[Dict]:
    """从现有文件加载已生成的题目"""
    try:
        with open(filename, "r", encoding="utf-8") as f:
            data = json.load(f)
        return data.get("questions", [])
    except FileNotFoundError:
        return []
    except Exception as e:
        print(f"加载已有题目时出错: {str(e)}")
        return []


def save_question_to_file(question: Dict, filename: str = "sanwei_questions.json"):
    """将单个题目写入JSON文件"""
    try:
        # 尝试读取现有文件
        try:
            with open(filename, "r", encoding="utf-8") as f:
                data = json.load(f)
        except FileNotFoundError:
            # 如果文件不存在，创建新结构
            data = {
                "metadata": {
                    "total_generated": 0,
                    "successful": 0,
                    "success_rate": "0%",
                    "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
                    "scenarios": scenarios,
                    "dimensions": base_dimensions,
                    "complexity_levels": complexity_levels
                },
                "questions": []
            }
        
        # 添加新题目
        data["questions"].append(question)
        
        # 更新统计数据
        data["metadata"]["total_generated"] = len(data["questions"])
        data["metadata"]["successful"] = sum(1 for q in data["questions"] if is_valid_question(q))
        data["metadata"]["success_rate"] = f"{(data['metadata']['successful'] / data['metadata']['total_generated']) * 100:.1f}%" if data['metadata']['total_generated'] > 0 else "0%"
        
        # 写回文件
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
            
    except Exception as e:
        print(f"保存题目到文件时出错: {str(e)}")


def print_question_details(question: Dict):
    """在终端打印题目详情"""
    print("=" * 60)
    print(f"题目详情:")
    print(f"场景: {question['scenario']}")
    print(f"维度: {question['dimension']}")
    print(f"复杂度: {question['complexity']}")
    print(f"生成状态: {'成功' if question['success'] else '失败'}")
    print("-" * 60)
    if question['success']:
        print(question['question'][:500] + "..." if len(question['question']) > 500 else question['question'])
    else:
        print(f"错误信息: {question['question']}")
    print("=" * 60)


def find_last_generated_index(questions: List[Dict], all_combinations: List[tuple]) -> int:
    """查找最后一个成功生成的题目在组合列表中的索引"""
    if not questions:
        return -1
    
    # 从后往前查找最后一个有效的题目
    for i in range(len(questions) - 1, -1, -1):
        question = questions[i]
        if is_valid_question(question):
            # 找到该题目在组合列表中的位置
            scenario = question['scenario']
            dimension = question['dimension']
            complexity = question['complexity']
            
            try:
                index = all_combinations.index((scenario, dimension, complexity))
                return index
            except ValueError:
                continue
    
    return -1


def generate_questions(filename: str = "sanwei_questions.json") -> List[Dict]:
    """生成所有三维组合的题目，支持从中断点继续执行"""

    # 注册信号处理器
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)
    
    questions = []
    
    # 生成所有可能的场景-维度-复杂度组合
    all_combinations = list(itertools.product(scenarios, base_dimensions, complexity_levels))
    
    total_questions = len(all_combinations)
    
    # 加载已有的题目
    existing_questions = load_existing_questions(filename)
    start_index = find_last_generated_index(existing_questions, all_combinations) + 1
    
    if start_index > 0:
        print(f"发现已有 {len(existing_questions)} 道题目，从第 {start_index + 1} 题开始继续生成...")
        questions.extend(existing_questions[:start_index])
    
    print(f"总共需要生成 {total_questions} 道题目")
    print(f"开始从索引 {start_index} 处生成...")
    
    # 按顺序使用场景-维度-复杂度组合
    for i in range(start_index, total_questions):
        if interrupted:
            print("收到中断信号，正在保存已生成的题目...")
            break
            
        scenario, dimension, complexity = all_combinations[i]
        print(f"正在生成题目 {i + 1}/{total_questions}: {scenario} - {dimension} - {complexity}")

        # 生成题目
        question = generate_question(scenario, dimension, complexity)
        questions.append(question)
        
        # 立即写入文件
        save_question_to_file(question, filename)
        
        # 在终端打印题目详情（仅显示前100个字符）
        print_question_details(question)

        # 添加延迟以避免API限制，随机化延迟时间
        delay = 2 + random.uniform(1, 3)
        print(f"等待 {delay:.2f} 秒...")
        time.sleep(delay)

    return questions


def save_questions(questions: List[Dict], filename: str = "sanwei_questions.json"):
    """保存题目到JSON文件"""

    # 过滤有效的题目
    valid_questions = [q for q in questions if is_valid_question(q)]
    
    # 计算成功率
    success_count = len(valid_questions)

    # 准备保存的数据
    data = {
        "metadata": {
            "total_generated": len(questions),
            "successful": success_count,
            "success_rate": f"{(success_count / len(questions)) * 100:.1f}%" if questions else "0%",
            "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
            "scenarios": scenarios,
            "dimensions": base_dimensions,
            "complexity_levels": complexity_levels
        },
        "questions": questions
    }

    # 保存到文件
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

    print(f"已保存 {len(questions)} 道题目到 {filename}")
    print(f"有效题目数量: {success_count}")
    print(f"成功率: {data['metadata']['success_rate']}")


def clean_empty_questions(filename: str = "sanwei_questions.json"):
    """清理空题目或生成失败的题目"""
    try:
        with open(filename, "r", encoding="utf-8") as f:
            data = json.load(f)
        
        original_count = len(data["questions"])
        # 过滤掉无效的题目
        data["questions"] = [q for q in data["questions"] if is_valid_question(q)]
        cleaned_count = len(data["questions"])
        
        # 更新统计数据
        data["metadata"]["total_generated"] = cleaned_count
        data["metadata"]["successful"] = cleaned_count
        data["metadata"]["success_rate"] = "100.0%" if cleaned_count > 0 else "0%"
        
        # 保存清理后的数据
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
            
        print(f"清理完成: 从 {original_count} 道题目中移除了 {original_count - cleaned_count} 道无效题目")
        print(f"剩余有效题目: {cleaned_count} 道")
        
    except Exception as e:
        print(f"清理题目时出错: {str(e)}")


def check_and_fix_json(filename: str = "sanwei_questions.json"):
    """检查并修复JSON文件中的问题"""
    try:
        with open(filename, "r", encoding="utf-8") as f:
            data = json.load(f)
        
        # 检查并修复数据结构
        if "metadata" not in data:
            data["metadata"] = {
                "total_generated": 0,
                "successful": 0,
                "success_rate": "0%",
                "generated_at": time.strftime("%Y-%m-%d %H:%M:%S"),
                "scenarios": scenarios,
                "dimensions": base_dimensions,
                "complexity_levels": complexity_levels
            }
        
        if "questions" not in data:
            data["questions"] = []
        
        # 重新计算统计数据
        total = len(data["questions"])
        successful = sum(1 for q in data["questions"] if is_valid_question(q))
        success_rate = f"{(successful / total) * 100:.1f}%" if total > 0 else "0%"
        
        data["metadata"]["total_generated"] = total
        data["metadata"]["successful"] = successful
        data["metadata"]["success_rate"] = success_rate
        
        # 保存修复后的数据
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
        
        print(f"JSON文件检查和修复完成，共 {total} 道题目，有效 {successful} 道，成功率 {success_rate}")
        return True
        
    except Exception as e:
        print(f"检查和修复JSON文件时出错: {str(e)}")
        return False


if __name__ == "__main__":
    print("开始生成商业场景察言观色能力三维题目...")
    print(f"基础维度数量: {len(base_dimensions)}")
    print(f"情境复杂度维度数量: {len(complexity_levels)}")
    print(f"场景数量: {len(scenarios)}")
    print(f"可能的题目总数: {len(scenarios) * len(base_dimensions) * len(complexity_levels)}")
    
    # 检查并修复JSON文件
    if os.path.exists("sanwei_questions.json"):
        print("检查并修复JSON文件...")
        check_and_fix_json()
        
        response = input("是否需要清理无效题目? (y/n，默认为n): ") or "n"
        if response.lower() == 'y':
            clean_empty_questions()
    
    # 生成所有三维组合的题目
    questions = generate_questions()

    # 保存题目
    save_questions(questions)

    # 打印一些统计信息
    valid_questions = [q for q in questions if is_valid_question(q)]
    print(f"\n成功生成 {len(valid_questions)} 道有效题目:")

    for i, q in enumerate(valid_questions[-3:], len(valid_questions)-2):  # 显示最后3道题目作为示例
        print(f"\n示例题目 {i}:")
        print(f"场景: {q['scenario']}")
        print(f"维度: {q['dimension']}")
        print(f"复杂度: {q['complexity']}")
        # 只显示前500个字符
        content = q['question'][:500] + "..." if len(q['question']) > 500 else q['question']
        print("内容:")
        print(content)
        print("-" * 50)